package com.sychip.fhc.app.wsn.screen


import androidx.compose.runtime.mutableStateListOf
import androidx.lifecycle.viewModelScope
import com.fhc.base.Async
import com.fhc.base.EventType
import com.fhc.base.FhcFlowEventBus
import com.fhc.base.FlowEventBusData
import com.fhc.view.WhileUiSubscribed
import com.sychip.fhc.MainApplication
import com.sychip.fhc.app.data.repo.WsnDeviceRepo
import com.sychip.fhc.app.data.repo.WsnDeviceRssiRepo
import com.sychip.fhc.app.data.repo.WsnRssiHisRepo
import com.sychip.fhc.app.data.source.dto.WsnDeviceRssiDto
import com.sychip.fhc.app.pref.PrefDataStoreIf
import com.sychip.fhc.app.todo.R
import com.sychip.fhc.app.wsn.nav.RouterAvgPerDto
import com.sychip.fhc.base.CommonUiState
import com.sychip.fhc.base.UiStatus
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import javax.inject.Inject


/**
 * ViewModel for the WsnList screen.
 *
 * @property rssiRepo
 * @constructor
 *
 * @param app
 */
@HiltViewModel
class WsnListViewModel @Inject constructor(
    app : MainApplication,
    override val prefDataStore: PrefDataStoreIf,
    override val rssiRepo: WsnDeviceRssiRepo,
    override val devRepo: WsnDeviceRepo,
    override val rssiHisRepo: WsnRssiHisRepo
) : WsnBaseViewModel(app, prefDataStore, rssiRepo, devRepo, rssiHisRepo) {

    open class MapDeviceRssiDto(
        val usbId: String = "",
        var fromDevId: String = "",
        var toDevId: String = "",
        var rssi: Int = 0,
        var dateTime: Long = System.currentTimeMillis(),
        var avg: String = "--",
        var per: String = "--",
    )
    /**
     * _dev db async
     */
    private val _devDbAsync = rssiRepo.observeLastRssi(usbId =usbId).map {
        handleRssiAsync(it)
    }.catch { emit(Async.Error(R.string.loading_task_error))
    }

    /**
     * Handle rssi async
     *
     * @param task
     * @return
     */
    private fun handleRssiAsync(task: List<WsnDeviceRssiDto>?): Async<List<WsnDeviceRssiDto>> {
        if (task == null) {
            return Async.Error(R.string.task_not_found)
        }
        return Async.Success(task.toMutableList())
    }

    val rssiAllFlow: StateFlow<CommonUiState<WsnDeviceRssiDto>> = _devDbAsync.map { task ->
        when (task) {
            Async.Loading -> {
                CommonUiState(status = UiStatus.Loading)
            }
            is Async.Error ->{
                CommonUiState( status = UiStatus.Error)
            }
            is Async.Success -> {
                CommonUiState( status = UiStatus.Success, dataList = task.data)
            }
        }

    }.onCompletion { cause ->
    }.stateIn(
        scope = viewModelScope,
        started = WhileUiSubscribed,
        initialValue = CommonUiState()
    )
    private val listMutex = Mutex()
    init {

        viewModelScope.launch {
            rssiAllFlow.collect { state ->
                if(state.status == UiStatus.Success) {
                    filterRssiLine()
                }
            }
        }

        viewModelScope.launch {
            FhcFlowEventBus.subscribe<FlowEventBusData> { event ->
                if (event.dataType == EventType.AvgPer) {
                    launch{
                        listMutex.withLock {
                            val avgPerDto = event.dataObj as RouterAvgPerDto
                            val oldAvgPerDto = avgPerData.find { it.fromDevId == avgPerDto.fromDevId && it.toDevId == avgPerDto.toDevId }
                            if (oldAvgPerDto == null) {
                                avgPerData.add(avgPerDto)
                            } else {
                                oldAvgPerDto.avg = avgPerDto.avg
                                oldAvgPerDto.per = avgPerDto.per
                            }
                            filterRssiLine()
                        }
                    }
                }
            }
        }
        observerFilterDto(afterFilterChanged =  {
            filterRssiLine()
        })
    }

    private val avgPerData: MutableList<RouterAvgPerDto> = mutableStateListOf()
    /**
     * _rssi filter flow
     */
    private val _rssiFilterFlow:MutableStateFlow<MutableList<MapDeviceRssiDto>> = MutableStateFlow( mutableListOf())
    val rssiFilterFlow: StateFlow<MutableList<MapDeviceRssiDto>> = _rssiFilterFlow.asStateFlow()

//    started = SharingStarted.WhileSubscribed(stopTimeoutMillis = 5000), // 无订阅5秒后停

    private fun filterRssiLine() {
        val result = filterLine(rssiAllFlow.value.dataList)
        val list:MutableList<MapDeviceRssiDto> = mutableStateListOf()
        result.forEach {
            var  avg = "--"
            var  per = "--"
            val avgPerDto = avgPerData.find {avgPerDto-> it.fromDevId == avgPerDto.fromDevId && it.toDevId == avgPerDto.toDevId }
            if (avgPerDto != null) {
                avg = avgPerDto.avg
                per = avgPerDto.per
            }
            list.add(MapDeviceRssiDto(it.usbId, it.fromDevId, it.toDevId, it.rssi, it.dateTime, avg, per))
        }
        _rssiFilterFlow.update { list.toMutableList() }
    }

    override fun clearAllData() {
        avgPerData.clear()
        super.clearAllData()
    }
}
